package pl.pelcra.cesar.spider.webparser;

import java.util.Date;

import org.apache.log4j.Logger;

import pl.pelcra.cesar.data.interfaces.ICommonData;
import pl.pelcra.cesar.spider.data.MapLangUrl;
import pl.pelcra.cesar.spider.webcrawler.CSWebURL;
import pl.pelcra.cesar.spider.webparser.interfaces.BasePageParser;
import pl.pelcra.cesar.tools.Tools;
import pl.pelcra.cesar.webrecorder.database.enums.DBLogStatus;
import pl.pelcra.cesar.webrecorder.database.tables.DBLog;
import pl.pelcra.cesar.webrecorder.database.tables.DBWeb_Record;

/**
 * Class extends from thread and parse pages to DBWeb_Recors objects.
 * 
 * @author margielewski
 * 
 */
public class WebParser extends Thread {

	private final BasePageParser basePageParser;
	private int j = 0;
	private final Logger logger = Logger.getLogger(WebParser.class);
	private final ICommonData<DBLog> logWebRecordThreadData;
	private final ICommonData<MapLangUrl> spiderThreadData;
	private final ICommonData<DBWeb_Record> webRecordThreadData;

	/**
	 * Main constructor WebParser class
	 * 
	 * @param spiderThreadData
	 *            class with MapLangUrl objects to parse
	 * @param webRecordThreadData
	 *            class that stores DBWeb_Record objects with parsed content of
	 *            page
	 * @param logWebRecordThreadData
	 *            class that stores DBLog objects with parsed error information
	 *            of parsing page
	 * @param parserClassName
	 *            string class name of BasePageParser from configuration file
	 * @param parserParameters
	 *            string value of parameters from configuration file transfer to
	 *            BasePageParser class
	 * @param politenessDelay
	 *            integer value of delay time to next politeness ask about next
	 *            page
	 */
	public WebParser(ICommonData<MapLangUrl> spiderThreadData,
			ICommonData<DBWeb_Record> webRecordThreadData,
			ICommonData<DBLog> logWebRecordThreadData, String parserClassName,
			String parserParameters, int politenessDelay) {
		this.spiderThreadData = spiderThreadData;
		this.webRecordThreadData = webRecordThreadData;
		this.logWebRecordThreadData = logWebRecordThreadData;

		this.basePageParser = Tools.loadClass(BasePageParser.class,
				parserClassName, new Object[] { parserParameters,
						politenessDelay });
	}

	/**
	 * function creates DBLog object from error of parsing page
	 * 
	 * @param webURL
	 *            webUrl object with link to parse page
	 * @param language
	 *            string value of language
	 * @param doc_id
	 *            id of page document
	 * @param traceback
	 *            error message
	 * @param details
	 *            details of error
	 * @return return object that contains information about error of parsing
	 *         page - this object is written to database
	 */
	private DBLog getDBLog(CSWebURL webURL, String language, String doc_id,
			String traceback, String details) {
		DBLog dbLog = new DBLog();

		dbLog.setDb_doc_id(doc_id);
		dbLog.setUrl(webURL.getURL());
		dbLog.setDate(new Date());
		dbLog.setStatus(DBLogStatus.ERR);
		dbLog.setDetails(details);
		dbLog.setTraceback(traceback);

		return dbLog;
	}

	/**
	 * function creates DBWeb_Record object using page parser
	 * 
	 * @param webURL
	 *            webUrl object with link to parse page
	 * @param language
	 *            string value of language
	 * @param doc_id
	 *            id of page document
	 * @return return object that contains parsed page to object - this object
	 *         is written to database
	 */
	private DBWeb_Record parsePage(CSWebURL webURL, String language,
			String doc_id) {
		if (this.basePageParser != null) {
			this.basePageParser.init(webURL, language, doc_id);

			if (this.basePageParser.isGetPageSuccess()) {
				return this.basePageParser.getDBWeb_Record();
			} else {
				this.logWebRecordThreadData.put(this.getDBLog(webURL, language,
						doc_id, this.basePageParser.getErrorMsg(),
						this.basePageParser.getErrorDetails() + " Lang="
								+ language));
				return null;
			}
		}
		return null;
	}

	/**
	 * overridden method from interface Runnable.
	 * 
	 * This method get MapLangUrl objects from class spiderThreadData until
	 * CrawlController process end putting new objects to list in
	 * spiderThreadData. From MapLangUrl object function gets language, url and
	 * then get content of page and parse page using BasePageParser object from
	 * configuration file. If parse success then put DBWeb_Record object to
	 * WebRecordThreadData class, if fails then put DBLog object to
	 * LogWebRecordThreadData class. Thread ands working after parse all
	 * MapLangUrl objects from spiderThreadData.
	 */
	@Override
	public void run() {
		this.logger.info("WebParser starts working");
		if (this.basePageParser != null) {
			MapLangUrl mapLangUrl;
			DBWeb_Record dbbWeb_Record = null;
			while (!this.spiderThreadData.isEndPutting()) {
				mapLangUrl = this.spiderThreadData.get();
				if (mapLangUrl != null) {
					this.logger.info(String.format("ParsePageId=%s",
							mapLangUrl.getId()));

					CSWebURL csWebURL = null;
					String url = "";
					int i = 0;

					for (String lang : mapLangUrl.keySet()) {

						csWebURL = mapLangUrl.get(lang);
						if (i == 0) {
							url = csWebURL.getURL();
						}

						if (csWebURL != null && csWebURL.hasData()) {
							dbbWeb_Record = this.parsePage(csWebURL, lang, url);

							if (dbbWeb_Record != null) {
								this.webRecordThreadData.put(dbbWeb_Record);
								this.logger.info(String.format(
										"Parsed %s, url=%s", ++this.j,
										csWebURL.getURL()));
							}
						}
						i++;
					}
				}
			}
		} else {
			this.logger.info("Cannot initialize BasePageParser.");
		}

		this.webRecordThreadData.endPutting();
		this.logWebRecordThreadData.endPutting();
		this.logger.info("WebParser ends working");
	}
}
